home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 November / EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso / earcd / giochi / amigainf.lha / Inform / examples / balances.inf < prev    next >
Text File  |  1995-08-02  |  70KB  |  1,774 lines

  1. ! ----------------------------------------------------------------------------
  2. !   Balances:  An exercise in parsing                       Release 2, 25/9/94
  3. !                                                             updated  6/10/94
  4. !
  5. !   This short story was written to demonstrate large-scale programming of
  6. !   the parser, and features multiple objects, complicated plurals, variable
  7. !   verbs, objects named by the player and questions.  The spell-casting
  8. !   system is written in a "safe" way so that it could easily be transplanted,
  9. !   and is as "object-oriented" as seemed sensible to the author.
  10. !
  11. !   A number of minor slips in Release 1 have been corrected, and those who
  12. !   reported them are gratefully thanked; and many suggestions have been
  13. !   added.  A few others I've reluctantly declined in the interests of
  14. !   keeping the source code reasonably clean as an example program
  15. !   which compiles as a Standard as well as an Advanced game.
  16. !   Oh, and apologies to all those who think lleps of rezrov is vorzer.
  17. !
  18. !   Needs Inform 5.4 or later to compile.
  19. !
  20. !   This is slightly updated because the original did not properly work as
  21. !   an Advanced game (it was originally written as Standard), because it
  22. !   rather lazily got the first 2-byte word of the property list for "name"
  23. !   by the usage  thing.name  rather than properly looking up the 0th word
  24. !   in the array by  (thing.&name)-->0  (thing.&name is the address of the
  25. !   list of data in the name property).  Anyway, sorry.
  26. ! ----------------------------------------------------------------------------
  27.  
  28. Switches d;
  29.  
  30. Constant Story "BALANCES";
  31. Constant Headline "^An Interactive Short Story^\
  32.              Copyright (c) 1994 by Graham Nelson.^";
  33.  
  34. Release 2;
  35.  
  36. Constant OBJECT_SCORE 5;
  37. Constant MAX_SCORE 51;
  38.  
  39. ! Constant DEBUG;
  40.  
  41. Include "Parser";
  42. Include "VerbLib";
  43.  
  44. ! ----------------------------------------------------------------------------
  45. !   The white featureless cubes from "Spellbreaker", which can be identified
  46. !   by being written on with the magic burin, so that their names are given
  47. !   by the player in the course of play
  48. !
  49. !   A particularly witty thing to do is to give several of them the same name,
  50. !   or to frotz some of them to distinguish them from the others...
  51. !   And the game will have no problem with this.
  52. ! ----------------------------------------------------------------------------
  53.  
  54. Attribute is_cube;
  55.  
  56. global cube_text_buffer data 8;
  57. global the_named_word = 0;
  58.  
  59. Fake_Action Baptise;
  60.  
  61. Class  cube_class
  62.   with number 0 0 0 0,
  63.        description "A perfect white cube, four inches on a side.",
  64.        parse_name
  65.        [ i j flag;
  66.             if (parser_action==##TheSame)
  67.             {   for (i=0:i<8:i++)
  68.                     if ((parser_one.&number)->i
  69.                         ~= (parser_two.&number)->i) return -2;
  70.                 return -1;
  71.             }
  72.             for (::i++)
  73.             {   j=NextWord(); flag=0;
  74.                 if (j=='cube' or 'white' ||
  75.                     (j=='featureless' or 'blank' &&
  76.                            ((self.&number)->0) == 0)) flag=1;
  77.                 if (j=='cubes')
  78.                 {   flag=1; parser_action=##PluralFound; }
  79.                 if (flag==0 && ((self.&number)->0) ~= 0)
  80.                 {   wn--;
  81.                     if (TextReader()==0) return i;
  82.                     for (j=0: j<8: j++)
  83.                         if ((self.&number)->j ~= cube_text_buffer->j)
  84.                             return i;
  85.                     flag=1;
  86.                 }
  87.                 if (flag==0) return i;
  88.             }
  89.        ],
  90.        article "a",
  91.        short_name
  92.        [ i; if (((self.&number)->0) == 0) print "featureless white cube";
  93.             else
  94.             {   print "~";
  95.                 while (((self.&number)->i) ~= 0)
  96.                     print char (self.&number)->i++;
  97.                 print "~ cube";
  98.             }
  99.             rtrue;
  100.        ],
  101.        plural
  102.        [;   RunRoutines(self, short_name); print "s";
  103.        ],
  104.        before
  105.        [ i; Baptise: wn = the_named_word;
  106.                      if (TextReader()==0) return i;
  107.                      for (i=0: i<8: i++)
  108.                          (self.&number)->i = cube_text_buffer->i;
  109.                      self.article="the";
  110.                      print "It is now called "; DefArt(self); ".";
  111.        ],
  112.   has  is_cube scored;
  113.  
  114. !  Copies word "wn" from what the player most recently typed, putting it as
  115. !  plain text into cube_text_buffer, returning false if no such word is there
  116.  
  117. [ TextReader point i j len;
  118.  
  119.    for (i=0:i<8:i++) cube_text_buffer->i = 0;
  120.    if (wn > parse->1) { wn++; rfalse; }
  121.    i=wn*4+1; j=parse->i; point=j+buffer; len=parse->(i-1);
  122.  
  123.    for (i=0:i<len && i<7:i++) cube_text_buffer->i = point->i;
  124.  
  125.    wn++; rtrue;
  126. ];
  127.  
  128. Object burin "magic burin"
  129.   with name "magic" "magical" "burin" "pen",
  130.        description
  131.           "This is a magical burin, used for inscribing objects with words \
  132.            or runes of magical import. Such a burin also gives you the \
  133.            ability to write spell scrolls.",
  134.        before
  135.        [; WriteOn:
  136.              if (second has is_cube)
  137.              {   if (second notin player)
  138.                      "To write on a cube, you need to be holding it first.";
  139.                  if (burin notin player)
  140.                      "You would need some powerful implement for that.";
  141.                  <<Baptise second>>;
  142.              }
  143.              if (second has is_spell_book)
  144.                  "If a burin could write in a spell book, you wouldn't need \
  145.                   the gnusto spell!";
  146.              if (second has is_scroll)
  147.                  "You cannot write just anything on the magic parchment of \
  148.                   a scroll: you can only ~copy~ a spell to it.";
  149.        ];
  150.  
  151. [ WriteOnSub; "Graffiti is banned."; ];
  152.  
  153. [ CopyToSub;
  154.   if (burin notin player) "You need to be holding the burin to copy a spell.";
  155.   if (second has is_spell_book)
  156.       "If a burin could write in a spell book, you wouldn't need \
  157.        the gnusto spell!";
  158.   if (second hasnt is_scroll) "You can only copy spells to scrolls.";
  159.   if (child(second)~=0)
  160.       "The scroll is already full of incantation.";
  161.   "The scroll is not blank, only illegible.";
  162. ];
  163.  
  164. ! ----------------------------------------------------------------------------
  165. !   Now the whole spell-casting system
  166. ! ----------------------------------------------------------------------------
  167.  
  168. Attribute is_spell;
  169. Attribute is_scroll alias talkable;    !  These are both
  170. Attribute is_spell_book alias female;  !  dodges, in case compiling in old V3
  171. Property long magic;
  172.  
  173. [ SpellName obj; print_addr (obj.&name)-->0; ];
  174.  
  175. Class  spell_class
  176.   with name "spell" "spells", article "the", number 0,
  177.        short_name
  178.        [; SpellName(self); print " spell"; rtrue;
  179.        ],
  180.        before
  181.        [; Examine: SpellName(self); print " spell:  ", object self; rtrue;
  182.        ],
  183.   has  is_spell;
  184.  
  185. Object memory "memory"
  186.   with capacity 5,
  187.        number 1,
  188.        before
  189.        [ i j k;
  190.          Examine:
  191.            objectloop (i in self) if (i.number==100) j++;
  192.            if (j>0)
  193.            {   print "The ";
  194.                objectloop (i in self)
  195.                    if (i.number==100)
  196.                    {   k++; SpellName(i);
  197.                        if (k==j-1) print " and ";
  198.                        if (k<j-1) print ", ";
  199.                    }
  200.                if (j==1) print " spell is"; else print " spells are";
  201.                print " yours forever.  Other than that, y";
  202.            }
  203.            else print "Y";
  204.            print "ou have ";
  205.            j=0; k=0;
  206.            objectloop (i in self) if (i.number<100) j++;
  207.            if (j>0)
  208.            {   print "the ";
  209.                objectloop (i in self)
  210.                    if (i.number<100)
  211.                    {   k++;
  212.                        PrintShortName(i);
  213.                        if (i.number==2) print " (twice)";
  214.                        if (i.number==3) print " (thrice)";
  215.                        if (i.number==4) print " (four times)";
  216.                        if (i.number>=5) print " (many times)";
  217.                        if (k==j-1) print " and ";
  218.                        if (k<j-1) print ", ";
  219.                    }
  220.            }
  221.            else print "no spells";
  222.            " memorised.";
  223.          Insert:
  224.            if (second.number==100) "You always know that spell.";
  225.            self.number=self.number+1;
  226.            print "Using your best study habits, you commit the ";
  227.            SpellName(second);
  228.            print " spell to memory";
  229.            if (second notin self) second.number=0;
  230.            move second to self;
  231.            second.number=second.number+1;
  232.            if (second.number==1) print ".";
  233.            if (second.number==2) print " once again.";
  234.            if (second.number==3) print " a third time.";
  235.            if (second.number>3) print " yet another time.";
  236.            if (self.number <= self.capacity) { new_line; rtrue; }
  237.            i=youngest(self); <Remove self i>;
  238.            "  You have so much buzzing around in your head, though, \
  239.               that it's likely something may have been forgotten \
  240.               in the shuffle.";
  241.          Remove:
  242.            if (second notin self || second.number==100) rtrue;
  243.            if (self.number>0) self.number=self.number-1;
  244.            second.number=second.number-1;
  245.            if (second.number==0) remove second;
  246.            rtrue;
  247.        ];
  248.  
  249. Object gnusto_spell "copy a scroll into your spell book" memory
  250.  class spell_class
  251.   with name "gnusto",
  252.        number 100,
  253.        magic
  254.        [ i a_book;
  255.             if (second has is_spell_book)
  256.                "Unlike scrolls, spell books are magically guarded against \
  257.                 the 'theft' of their lore.";
  258.             if (second==0 || second hasnt is_scroll)
  259.                "Your spell fizzles vaguely out.";
  260.             if (second notin player)
  261.                 "A gnusto spell would require close scrutiny of the scroll \
  262.                  it is to copy: which you do not seem to be holding.";
  263.             objectloop (i in player)
  264.                 if (i has is_spell_book) a_book=i;
  265.             if (a_book==0)
  266.                 "Your spell fails, as you have no spell book.";
  267.             i=child(second);
  268.             if (i==0 || i hasnt is_spell)
  269.             {   print "Your spell fails, as "; DefArt(second);
  270.                 " is illegible.";
  271.             }
  272.             <Learn a_book i>; remove second;
  273.             print "Your spell book begins to glow softly.  Slowly, ornately, \
  274.                    the words of "; DefArt(i); " are inscribed, \
  275.                    glowing even more brightly then the book itself.  \
  276.                    The book's brightness fades, but the spell remains!  \
  277.                    However, the scroll on which it was written vanishes as \
  278.                    the last word is copied.";
  279.        ];
  280.  
  281. Class  spell_book_class
  282.   with magic 0,
  283.        capacity 16,
  284.        before
  285.        [ p i; Open, Close:
  286.               CDefArt(self); " is always open to the right place, but it \
  287.               is also always closed. This eliminates tedious leafing and \
  288.               hunting for spells.  Many lives have been saved by this \
  289.               magical innovation.";
  290.           Attack:
  291.               print "When you are done, "; DefArt(self); " remains unmarred.";
  292.           Learn:
  293.               if (self.magic==0) "(This spell book has no pages.)";
  294.               p = self.magic;
  295.               for (i=0:i<self.capacity && (p-->i)~=0:i++) ;
  296.               if (i==self.capacity) rtrue;
  297.               p-->i = second;
  298.               rtrue;
  299.        ],
  300.        after
  301.        [ p i j; Examine:
  302.               if (self.magic==0) "(This spell book has no pages.)";
  303.               p = self.magic;
  304.               for (i=0:i<self.capacity && (p-->i)~=0:i++)
  305.               {   j=p-->i; <Examine j>; new_line;
  306.               }
  307.               rtrue;
  308.        ],
  309.   has  is_spell_book;
  310.  
  311. Class  scroll_class
  312.   with parse_name
  313.        [ i j; j=-1;
  314.               if (self has general)
  315.               {   if (child(self)~=0 && child(self) has is_spell)
  316.                       j=(child(self).&name)-->0; else j='illegible';
  317.               }
  318.               while (NextWord()==j or 'scroll' or (self.&name)-->0) i++;
  319.               return i;
  320.        ],
  321.        before
  322.        [ i; Examine:
  323.             i=child(self);
  324.             give self general;
  325.             if (i==0 || i hasnt is_spell)
  326.                 "The scroll has faded, and you cannot read it.";
  327.             print "The scroll reads ~"; <Examine i>; "~.";
  328.        ],
  329.        invent
  330.        [;   if (inventory_stage==2 && self has general)
  331.             {   if (child(self)==0 || child(self) hasnt is_spell)
  332.                     print " (which is illegible)";
  333.                 else
  334.                 {   print " (of "; DefArt(child(self)); print ")"; }
  335.             }
  336.        ],
  337.   has  is_scroll;
  338.  
  339. [ ReadableSpell i j k;
  340.   if (scope_stage==1) return 1;
  341.   if (scope_stage==2)
  342.   {   objectloop (i in player)
  343.           if (i has is_spell_book)
  344.           {   for (k=0:k<i.capacity && (i.magic)-->k~=0:k++)
  345.               {   j=(i.magic)-->k; PlaceInScope(j);
  346.               }
  347.           }
  348.       rtrue;
  349.   }
  350.   "No such spell is in any spell book you're holding.";
  351. ];
  352.  
  353.  
  354. [ SpellsSub; <Examine memory>; ];
  355.  
  356. [ LearnSub; if (location==thedark)
  357.                 print "(The magic writing of the spells casts enough light \
  358.                         that you can read them.)^";
  359.             <Insert memory noun>;
  360. ];
  361.  
  362. global the_spell_was = gnusto_spell;
  363.  
  364. [ CastOneSub; <Cast the_spell_was noun>; ];
  365.  
  366. Property long unmagic;
  367.  
  368. [ CastSub;
  369.   the_spell_was = noun; <Remove memory noun>;
  370.  
  371.   if (noun has general)
  372.   {   give noun ~general;
  373.       if (RunRoutines(noun,unmagic)~=0) rfalse;
  374.       "Nothing happens.";
  375.   }
  376.  
  377.   if (second~=0)
  378.   {   ResetVagueWords(second);                     ! Set "it", "him", "her"
  379.       if (RunRoutines(second,before)~=0) rfalse;   ! Run before routine(s)
  380.   }
  381.   if (RunRoutines(noun,magic)~=0) rfalse;
  382.   "Nothing happens.";
  383. ];
  384.  
  385. [ InScope i;
  386.   if (verb_word=='c#cast' or 'cast')
  387.       objectloop (i in memory) PlaceInScope(i);
  388.   rfalse;
  389. ];
  390.  
  391. [ ParserError;
  392.   if (verb_word=='cast')
  393.       "You have not learned such a spell.";
  394.   rfalse;
  395. ];
  396.  
  397. [ UnknownVerb word i;
  398.   objectloop (i in memory)
  399.       if (word==(i.&name)-->0) { the_spell_was = i; return 'c#cast'; }
  400.   rfalse;
  401. ];
  402.  
  403. [ PrintVerb v;
  404.   if (v=='c#cast') { print "cast a spell at"; rtrue; }
  405.   rfalse;
  406. ];
  407.  
  408. ! ----------------------------------------------------------------------------
  409. !   And now, on with the story.  First, some global variables:
  410. ! ----------------------------------------------------------------------------
  411.  
  412. global prepared_flag = 0;          !  Prepared for resurrection?
  413. global hearing_good = 0;           !  Sharp hearing?
  414. global number_filled = 0;          !  Sockets in the temple filled
  415. global all_my_spells data 32;      !  Array for contents of your spell book
  416. global helistars_spells data 32;   !  ...and Helistar's
  417.  
  418. ! ----------------------------------------------------------------------------
  419. !   A "questions" verb.  Thus,
  420. !      "who is my friend helistar"
  421. !      "what was the great change"
  422. !   and so on are recognised.
  423. ! ----------------------------------------------------------------------------
  424.  
  425. Object questions "qs";
  426. [ QuerySub;
  427.   print_paddr noun.description; new_line;
  428. ];
  429. [ Topic i;
  430.   if (scope_stage==1) return 0;
  431.   if (scope_stage==2)
  432.   {   objectloop (i in questions) PlaceInScope(i);
  433.       rtrue;
  434.   }
  435.   "At the moment, even the simplest questions confuse you.";
  436. ];
  437.  
  438. Object q1 "q1" questions
  439.   with name "helistar" "my" "friend" "colleague",
  440.        description
  441.       "Helistar is your colleague, an Enchanter like you who has been much \
  442.        on your mind lately.  She has been investigating some very dark \
  443.        magic indeed, and seems not to be around any more.  You feel rather \
  444.        vague about the details.";
  445. Object q2 "q2" questions
  446.   with name "magical" "magic" "burin",
  447.        description "A burin is an engraving and writing tool.";
  448. Object q3 "q3" questions
  449.   with name "change" "great",
  450.        description
  451.       "Something you had a lot to do with, but what exactly?  No, it's gone.";
  452. Object q4 "q4" questions
  453.   with name "cyclops",
  454.        description
  455.       "A one-eyed giant, usually hostile.  (Don't they teach anything at \
  456.        adventurer school these days?)";
  457. Object q5 "q5" questions
  458.   with name "grue",
  459.        description
  460.       "The grue is a sinister, lurking presence in the dark places of the \
  461.        earth. Its favorite diet is adventurers, but its insatiable appetite \
  462.        is tempered by its fear of light. No grue has ever been seen by the \
  463.        light of day, and few have survived its fearsome jaws to \
  464.        tell the tale.";
  465. Object q6 "q6" questions
  466.   with name "grimoire",
  467.        description
  468.       "According to Chambers English Dictionary, a grimoire is ~a magician's \
  469.        book for calling up spirits~.";
  470.  
  471. ! ----------------------------------------------------------------------------
  472. !   Some multiple objects, coins in fact, coded in deluxe fashion:
  473. ! ----------------------------------------------------------------------------
  474.  
  475. Attribute is_coin;
  476.  
  477. Class  coin_class
  478.   with name "coin",
  479.        description "A round unstamped disc, presumably part of the local \
  480.            currency.",
  481.        parse_name
  482.        [ i j w;
  483.          if (parser_action==##TheSame)
  484.          {   if ((parser_one.&name)-->0 == (parser_two.&name)-->0) return -1;
  485.              return -2;
  486.          }
  487.          w=(self.&name)-->0;
  488.          for (::i++)
  489.          {   j=NextWord();
  490.              if (j=='coins') parser_action=##PluralFound;
  491.              else if (j~='coin' or w) return i;
  492.          }
  493.        ],
  494.   has  is_coin;
  495.  
  496. Class  gold_coin_class
  497.  class coin_class,
  498.   with name "gold",
  499.        plural "gold coins";
  500. Class  silver_coin_class
  501.  class coin_class,
  502.   with name "silver",
  503.        plural "silver coins";
  504. Class  bronze_coin_class
  505.  class coin_class,
  506.   with name "bronze",
  507.        plural "bronze coins";
  508.  
  509. Object coin1 "silver coin"
  510.  class silver_coin_class;
  511.  
  512. [ TossCoinSub; if (noun notin player) "You need to be holding the coin first.";
  513.   move noun to parent(player);
  514.   if (location==thedark) "You throw it away into the darkness.";
  515.   if (random(20)==1) "You toss the coin, and it lands... on its edge, \
  516.       amazingly.";
  517.   "You toss the coin, and it comes up... blank, since neither side is \
  518.    marked.";
  519. ];
  520.  
  521. ! ----------------------------------------------------------------------------
  522. !   The player's spell book, and three initial spells (to go with gnusto):
  523. ! ----------------------------------------------------------------------------
  524.  
  525. Object spell_book "spell book"
  526.  class spell_book_class,
  527.   with name "spell" "book" "my" "spellbook",
  528.        description "My Spell Book^";
  529.  
  530. Object frotz_spell "cause an object to give off light"
  531.  class spell_class,
  532.   with name "frotz",
  533.        magic
  534.        [;  if (second==0) "There is a brief, blinding flash of light.";
  535.            if (second has animate)
  536.                "The spell, not designed for living creatures, goes sour.";
  537.            if (parent(second)==compass)
  538.                "The spell dissipates vaguely.";
  539.            give second light;
  540.       print "There is an almost blinding flash of light as "; DefArt(second);
  541.       print " begins to glow!  It slowly fades to a less painful level, but ";
  542.       DefArt(second); " is now quite usable as a light source.";
  543.        ],
  544.        unmagic
  545.        [;  if (second==0) "There is a brief moment of deep darkness.";
  546.            if (second has animate)
  547.                "The spell, not designed for living creatures, goes sour.";
  548.            if (parent(second)==compass)
  549.                "The spell dissipates vaguely.";
  550.            if (second hasnt light)
  551.            {   CDefArt(second); " isn't producing light as it is."; }
  552.            give second ~light;
  553.       print "A pool of darkness coagulates around "; DefArt(second);
  554.       print " but slowly fades back to normality.  Still, ";
  555.       DefArt(second); " is no longer any kind of light source.";
  556.        ];
  557.  
  558. Object rezrov_spell "open even locked or enchanted objects"
  559.  class spell_class,
  560.   with name "rezrov",
  561.        magic
  562.        [;  if (second==0) "The world is open already.";
  563.            if (second has animate)
  564.                "It might be a boon to surgeons if it worked, but it doesn't.";
  565.            if (second has open || second hasnt openable)
  566.                "It doesn't need opening.";
  567.            if (second hasnt locked)
  568.            {   give second open; CDefArt(second); " opens obediently.  \
  569.                Like swatting a fly with a sledge hammer, if you ask me.";
  570.            }
  571.            give second open ~locked;
  572.            print "Silently, "; DefArt(second); " swings open.";
  573.        ],
  574.        unmagic
  575.        [;  if (second==0) "The world is closed already.";
  576.            if (second has animate)
  577.                "Happily, that is unnecessary.";
  578.            if (second has locked || second hasnt lockable)
  579.                "It doesn't need locking.";
  580.            give second ~open locked;
  581.            print "Silently, "; DefArt(second); " swings shut and locks.";
  582.        ];
  583.  
  584. Object yomin_spell "mind probe"
  585.  class spell_class,
  586.   with name "yomin",
  587.        magic
  588.        [;  if (second==0 || second hasnt animate)
  589.                "That must be either vegetable or mineral.";
  590.            if (second==player) "You give yourself a mild headache.";
  591.            print "You look into the rather ordinary thoughts of ";
  592.            DefArt(second); ".";
  593.        ],
  594.        unmagic
  595.        [;  if (second==0 || second hasnt animate)
  596.                "That must be either vegetable or mineral.";
  597.            if (second==player) "You give yourself a mild headache.";
  598.            CDefArt(second); " is rather shocked, for some reason.";
  599.        ];
  600.  
  601. ! ----------------------------------------------------------------------------
  602. !   The first scene: the Hut and its (rather easy) secret 
  603. ! ----------------------------------------------------------------------------
  604.  
  605. Object Hut "Ramshackle Hut"
  606.   with description
  607.           "Until quite recently, someone lived here, you feel sure.  \
  608.            Now the furniture is matchwood and \
  609.            the windows are glassless.  Outside, it is a warm, sunny day, \
  610.            and grasslands extend to the low hills on the horizon.",
  611.        out_to Grasslands,
  612.        cant_go "There's only the one room: better go ~out~.",
  613.        name "windows" "grasslands" "grass" "hills",
  614.   has  light;
  615.  
  616. Nearby furniture "wooden furniture"
  617.   with name "furniture" "broken" "wood" "wooden",
  618.        before
  619.        [;  Examine, Search, LookUnder:
  620.                self.before=0; score=score+5;
  621.                move h_box to player;
  622.                "Searching through the furniture, which is good for nothing \
  623.                 but firewood now, you come across an old cedarwood box.";
  624.        ],
  625.   has  scenery;
  626.  
  627. Object h_box "cedarwood box"
  628.   with name "cedar" "cedarwood" "wooden" "box",
  629.        description "The box bears the calligraphed initial H."
  630.   has  container openable lockable locked;
  631.  
  632. Nearby helistars_book "Helistar's grimoire"
  633.  class spell_book_class,
  634.   with name "grimoire" "helistar" "helistars",
  635.        description "This must be the grimoire of dangerous spells kept by \
  636.                     your irresponsible friend Helistar.  Many pages are \
  637.                     missing, but a few spells remain:^",
  638.   has  proper;
  639.  
  640. ! ----------------------------------------------------------------------------
  641. !   Grasslands and the valley
  642. ! ----------------------------------------------------------------------------
  643.  
  644. Object Grasslands "Grasslands, near Hut"
  645.   with name "grasslands" "grass" "hut" "path",
  646.        description
  647.           "The grasslands sway over low hills in all directions: it is a \
  648.            peaceful wilderness, broken only by this hut and a faint path \
  649.            to the north.",
  650.        in_to Hut,
  651.        n_to Valley,
  652.        cant_go "You wander around for a while but end up back at the hut."
  653.   has  light;
  654.  
  655. Object Valley "Pocket Valley"
  656.   with name "valley" "trail",
  657.        description
  658.           "A pleasant pocket valley in the grassy hills, through which a \
  659.            trail runs north-to-south.",
  660.        n_to "The trail runs out to nothing, and you retreat for fear of \
  661.              getting so lost you couldn't find the hut again by nightfall.",
  662.        cant_go "You wander around the pleasant valley, but are afraid to \
  663.                 lose sight of the trail.",
  664.        s_to Grasslands
  665.   has  light;
  666.  
  667. [ RideSub; print "You can hardly ride "; IndefArt(noun); "."; ];
  668.  
  669. Nearby horse "horse"
  670.   with short_name
  671.        [; if (self has general) print "winged horse";
  672.           else print "chestnut horse";
  673.           rtrue;
  674.        ],
  675.        parse_name
  676.        [ i j; if (self has general) j='winged'; else j=-1;
  677.           while (NextWord()==j or 'horse' or 'chestnut') i++;
  678.           return i;
  679.        ],
  680.        describe
  681.        [;  print "There is "; InDefArt(self);
  682.            " here, munching on a pile of oats.";
  683.        ],
  684.        before
  685.        [;  Cast: if (the_spell_was == bozbar_spell)
  686.                  {   give self general;
  687.                     "A pair of handsome brown wings suddenly appears on \
  688.                      the horse's powerful shoulders.  The horse turns in a \
  689.                      complete circle, a look of puzzlement on his face.";
  690.                  }
  691.                  if (the_spell_was == yomin_spell)
  692.                     "He is mainly thinking about oats.  Partly who you are \
  693.                      and what you're up to, but mainly oats.";
  694.            Enter: <<Ride self>>;
  695.            Ride: if (horse hasnt general)
  696.                     "You ride around for a while, exercising the horse, but \
  697.                      soon enough he tires of this and pointedly brings you \
  698.                      back to the oats.  Obligingly you dismount and he \
  699.                      begins grazing again.";
  700.  
  701.            print "You begin to ride north.  Then, slowly at first but with \
  702.                   increasing sureness, the horse begins beating its powerful \
  703.                   wings.  You rise majestically through the air, sailing \
  704.                   gracefully across a chasm where the hills fall away.  \
  705.                   The horse lands gently on the far side and deposits you, \
  706.                   taking to the skies again.^";
  707.            PlayerTo(Edge); rtrue;
  708.        ],
  709.   has  animate;
  710.  
  711. Nearby oats "pile of oats"
  712.   with name "oats" "pile" "of",
  713.        before
  714.        [;  Examine, Search, LookUnder:
  715.                self.before=0;
  716.                move shiny_scroll to player; score=score+5;
  717.                "Sifting through the oats, you find a shiny scroll!  Lucky \
  718.                 you got to it before the horse did.";
  719.            Take:  "What would you want with all those oats?";
  720.        ],
  721.   has  scenery;
  722.  
  723. Object shiny_scroll "shiny scroll"
  724.  class scroll_class,
  725.   with name "shiny";
  726.  
  727. Object bozbar_spell "cause an animal to sprout wings" shiny_scroll
  728.  class spell_class,
  729.   with name "bozbar",
  730.        magic
  731.        [;  if (second==0 || second hasnt animate)
  732.                "The spell dies away in vain.";
  733.            if (second==player)
  734.                "Your elbows twitch, but there is no other effect.";
  735.            print "For a moment, "; DefArt(second);
  736.            " looks highly discomforted, but the moment passes.";
  737.        ],
  738.        unmagic
  739.        [;  if (second==0 || second hasnt animate)
  740.                "The spell dies away in vain.";
  741.            if (second==player) "What wings?";
  742.            if (second==horse && horse has general)
  743.            {   give horse ~general;
  744.                "The Enchanter giveth, and the Enchanter taketh away.  \
  745.                 The horse looks disconsolate but returns to the oats.";
  746.            }
  747.            CDefArt(second); " has no wings to lose.";
  748.        ];
  749.  
  750. ! ----------------------------------------------------------------------------
  751. !   The Chasm and the snake
  752. ! ----------------------------------------------------------------------------
  753.  
  754. Object Edge "Edge of Chasm"
  755.   with name "wide" "chasm" "road" "daffodils",
  756.        description
  757.           "The road ends suddenly at a wide chasm.  The road leads upward \
  758.            to the north, and you can see it continuing on the southern side \
  759.            of the chasm.",
  760.        u_to Up_Road, n_to Up_Road,
  761.        cant_go "The chasm is too perilous to approach.  The only safe way is \
  762.                up and to the north.",
  763.        before
  764.        [;  Jump: deadflag=1; "You jump bravely into the chasm, and plunge... \
  765.                gracefully through the air.  (It gets a bit less noble and \
  766.                airy after that.)";
  767.        ],
  768.   has  light;
  769.  
  770. Nearby snake "hissing snake"
  771.   with name "hissing" "snake",
  772.        initial
  773.          "Lying in a tight coil at the edge of the chasm is a hissing snake.",
  774.        life
  775.        [; "The snake hisses angrily!"; ],
  776.        before
  777.        [;  Cast: if (the_spell_was == urbzig_spell)
  778.                  {   remove self;
  779.                      snakes_cube.initial =
  780.                  "Beside a clump of daffodils is a featureless white cube.";
  781.                      "The snake is replaced by a clump of daffodils.";
  782.                  }
  783.                  if (the_spell_was == bozbar_spell)
  784.                  {   deadflag=1; remove self;
  785.                      snakes_cube.initial =
  786.                  "A featureless cube rests where the snake took off from.";
  787.                      "The snake is transformed into a huge, winged serpent, \
  788.                       a dragon which bellows and leaps out into the chasm, \
  789.                       backwinging furiously... and knocking you over the \
  790.                       edge quite by accident.";
  791.                  }
  792.                  if (the_spell_was == yomin_spell)
  793.                      "Horrid reptilian thoughts insinuate their way into you.";
  794.        ],
  795.   has  animate;
  796.  
  797. Nearby snakes_cube "cube"
  798.  class cube_class,
  799.   with initial
  800.          "The snake appears to be curled around a featureless white cube.",
  801.        before
  802.        [; if (snake notin nothing) "The snake won't let you near that cube!";
  803.        ];
  804.  
  805. ! ----------------------------------------------------------------------------
  806. !   The crest of the hill; Icarus the tortoise; the chewed scroll
  807. ! ----------------------------------------------------------------------------
  808.  
  809. Object Up_Road "Crest of Hill"
  810.   with description
  811.           "The road crosses the top of a ridge here, sloping downwards to \
  812.            the south and the northwest.  A track diverges to east.",
  813.        nw_to Cave_Mouth, s_to Edge, d_to Edge, e_to Track,
  814.   has  light;
  815.  
  816. Nearby tortoise "tortoise"
  817.   with name "tortoise" "turtle",
  818.        initial "A tortoise ambles along the road, extremely slowly.",
  819.        life
  820.        [; "The tortoise (slowly) turns its neck to look at you (stupidly).";
  821.        ],
  822.        before
  823.        [; Cast: if (the_spell_was == urbzig_spell)
  824.                     "Just how safe do you want your surroundings to be?";
  825.                 if (the_spell_was == bozbar_spell)
  826.                 {   move chewed_scroll to parent(self); remove self;
  827.                     StartDaemon(self); score=score+5;
  828.                     "The tortoise seems to be incapable of expressing \
  829.                      surprise, but is now soaring away high in the sky.  \
  830.                      Something rather grubby is left behind.";
  831.                 }
  832.                 if (the_spell_was == yomin_spell)
  833.                     "For a moment you think there is nothing there, as you \
  834.                      chew absentmindedly on a leaf.  But somewhere inside \
  835.                      the tortoise is a sense of wonder at the amazing blue \
  836.                      canopy of the sky.";
  837.        ],
  838.        daemon
  839.        [ i; if (location ~= Up_Road or Track || random(6)~=1) rfalse;
  840.           if (random(4)==1 && self hasnt general)
  841.           {   move feather to location; give self general;
  842.               "^A tortoise-feather flutters to the ground before you!";
  843.           }
  844.           i=random(3);
  845.           if (i==1) print "^High in the sky,";
  846.           if (i==2) print "^Far above you,";
  847.           if (i==3) print "^Tiny in the blue sky,";
  848.           " a tortoise flaps across the sun.";
  849.        ],
  850.   has  animate;
  851.  
  852. Object torn_scroll "torn scroll"
  853.  class scroll_class,
  854.   with name "torn";
  855.  
  856. Nearby lobal_spell "sharpen hearing"
  857.  class spell_class,
  858.   with magic
  859.        [;  if (second==0 || second hasnt animate)
  860.                "There is a loud bang in your ear, but no other effect.";
  861.            if (second==player)
  862.            {   if (hearing_good==1) "There is no further effect.";
  863.                hearing_good=1; StartTimer(self, 5);
  864.                "Nothing happens, possibly because those butterflies on the \
  865.                 other side of the hill keep distracting you.";
  866.            }
  867.            CDefArt(second);
  868.            " is no doubt grateful for the gift of sharper hearing.";
  869.        ],
  870.        unmagic
  871.        [;  if (second==0 || second hasnt animate)
  872.                "There is a brief silence, but no other effect.";
  873.            if (second==player) { StopTimer(self); hearing_good=0; "Pardon?"; }
  874.            CDefArt(second);
  875.            " is no doubt grateful not to have to listen to you.";
  876.        ],
  877.        time_left 0,
  878.        time_out
  879.        [;  if (hearing_good==0) rfalse;
  880.            hearing_good=0;
  881.            "^Those wretched butterflies finally shut up.";
  882.        ],
  883.        name "lobal";
  884.  
  885. Object chewed_scroll "chewed scroll"
  886.  class scroll_class,
  887.   with initial "It looks as if the tortoise was chewing something - once \
  888.                 it might have been a scroll, but now it's chewed up like \
  889.                 a lettuce leaf.",
  890.        before
  891.        [;  Cast: if (the_spell_was == caskly_spell)
  892.                  {   move torn_scroll to parent(self);
  893.                      remove self; score=score+5;
  894.                      "Before your eyes, the scroll begins to repair itself, \
  895.                       failing only at the very last tear.  Not quite perfect \
  896.                       perhaps, but certainly a readable, if torn scroll.";
  897.                  }
  898.        ],
  899.   with name "chewed";
  900.  
  901. Object feather "tortoise feather"
  902.   with name "tortoise" "feather",
  903.        description
  904.           "Possibly your rarest, and also least valuable, possession.";
  905.         
  906. ! ----------------------------------------------------------------------------
  907. !   The cave mouth and the perfect sapphire
  908. ! ----------------------------------------------------------------------------
  909.  
  910. Object Cave_Mouth "Cave Mouth"
  911.   with name "gorse" "footpath" "cave" "mouth",
  912.        description
  913.           "This is a cave mouth, at one end of a road which winds southeast \
  914.            over rising ground.  The entrance west to the caves is dark.  \
  915.            Only a footpath runs further north, into gorse.",
  916.        u_to Up_Road, se_to Up_Road, in_to Iron_Door, w_to Iron_Door,
  917.        n_to Footpath
  918.   has  light;
  919.  
  920. Nearby Iron_Door "iron door"
  921.   with name "iron" "door" "heavy",
  922.        description "It just looks like an ordinary heavy iron door.",
  923.        door_dir
  924.        [; if (location==Cave_Mouth) return w_to; return e_to;
  925.        ],
  926.        door_to
  927.        [; if (location==Cave_Mouth) return In_Cave;
  928.           return Cave_Mouth;
  929.        ],
  930.        describe
  931.        [; if (self has open) "^The iron door stands open.";
  932.           if (self hasnt locked) "^The iron door is unlocked but shut.";
  933.           "A heavy iron door bars the cave mouth.";
  934.        ],
  935.        found_in  In_Cave  Cave_Mouth
  936.   has  static door openable locked lockable;
  937.  
  938. !  Cf. T. S. Eliot, "Burnt Norton" II:
  939.  
  940. Nearby sapphire "perfect sapphire"
  941.   with name "perfect" "sapphire" "gemstone" "gem",
  942.        initial "Clotted in the mud beside the door is a perfect sapphire.",
  943.        before
  944.        [;  Examine: remove self; move caskly_spell to memory;
  945.                     <Learn spell_book caskly_spell>;
  946.                     caskly_spell.number=100;
  947.                     "As you gaze into the perfect blue of the sapphire, \
  948.                      you feel your mind begin to reel.  Unable to bear \
  949.                      the naked sight of perfection, you look away, ashamed.  \
  950.                      As you do so, the sapphire cracks and wastes away to \
  951.                      thin hot dust.  But something remains, something in your \
  952.                      mind...";
  953.        ];
  954.  
  955. Object caskly_spell "cause perfection"
  956.  class spell_class,
  957.   with name "caskly",
  958.        magic
  959.        [;  if (second==0) "Trying to make everything perfect was a little \
  960.                            too ambitious.";
  961.            if (second==player) "Oh, don't be too hard on yourself.";
  962.            if (second==helistars_book)
  963.                "Your spell is not powerful enough to restore the lost pages.";
  964.            CDefArt(second); " looks pretty perfect as is.";
  965.        ];
  966.  
  967. ! ----------------------------------------------------------------------------
  968. !   Inside the Cave, the powerful urbzig spell and its consequences
  969. ! ----------------------------------------------------------------------------
  970.  
  971. Object In_Cave "Inside Cave"
  972.   with description
  973.           "A wide but shallow cave not far inside the hill.  There is no \
  974.            obvious exit, except for the way you came in.",
  975.        out_to
  976.        [;  if (CoinsIn(left_pan)+CoinsIn(right_pan) < 6)
  977.                "Something bars your way, and you hear \
  978.                 the scales jangling militantly.  You were trying to \
  979.                 steal its coins!";
  980.            if (scales.number~=0) "Something bars your way, and you hear \
  981.                the scales jangle slightly with energy.";
  982.            return Iron_Door;
  983.        ],
  984.        cant_go "The only way is back ~out~ through the iron door.",
  985.        after
  986.        [;  Take: if (parent(noun)==left_pan or right_pan)
  987.                  {   print "Taken from "; DefArt(parent(noun)); "."; }
  988.        ];
  989.  
  990. Nearby cave_cube "cube"
  991.  class cube_class,
  992.   with initial "Balanced on a rock formation is a featureless white cube.";
  993.  
  994. Nearby scales "pair of scales"
  995.   with name "pair" "of" "scales" "pans", number 0,
  996.        describe
  997.        [;  print "^A fair-sized pair of scales hangs from a bracket in the \
  998.                   cave wall.  ";
  999.            if (self.number==0)  "The scales are balanced.";
  1000.            if (self.number==1)  "The left-hand side is higher.";
  1001.            "The right-hand side is higher.";
  1002.        ],
  1003.        before
  1004.        [;  "There are left and right hand pans, which you should refer to \
  1005.             individually.";
  1006.        ],
  1007.   has  static supporter;
  1008.  
  1009. Class  pan_class
  1010.   with name "pan" "side" "tray",
  1011.        before
  1012.        [;  Receive: if (noun has is_scroll || noun has is_coin) rfalse;
  1013.            if (noun==feather) rfalse;
  1014.            "The pans gleam with what almost seems greed, and somehow they \
  1015.             contrive to nudge your hand past them with your worthless and \
  1016.             boring item.";
  1017.        ],
  1018.        after
  1019.        [ i j d w1 w2;  Receive, LetGo: i=scales.number;
  1020.            objectloop (j in left_pan) w1=w1 + WeightOf(j);
  1021.            objectloop (j in right_pan) w2=w2 + WeightOf(j);
  1022.            if (w1==w2) scales.number=0;
  1023.            if (w1 > w2) scales.number=-1;
  1024.            if (w1 < w2) scales.number=1;
  1025.            j=scales.number; d=(w2-w1)*(scales.number);
  1026.            if (j==i) rfalse;
  1027.            if (j==0) "The scales come into balance.";
  1028.            if (j==1) print "The left pan "; else print "The right pan ";
  1029.            if (d==1) "very slowly rises up.";
  1030.            "rises up.";
  1031.        ],
  1032.   has  supporter scenery;
  1033.  
  1034. [ WeightOf obj;
  1035.   if (obj==bronze_coin) return 2;
  1036.   if (obj has is_scroll || obj==feather) return 1;
  1037.   return 3;
  1038. ];
  1039.  
  1040. [ CoinsIn obj i c;
  1041.   objectloop (i in obj) if (i has is_coin) c++;
  1042.   return c;
  1043. ];
  1044.  
  1045. Nearby left_pan "left pan"
  1046.  class pan_class,
  1047.   with name "left";
  1048. Nearby right_pan "right pan"
  1049.  class pan_class,
  1050.   with name "right";
  1051. Object bronze_coin "bronze coin" left_pan
  1052.  class bronze_coin_class;
  1053. Object coin3 "gold coin" left_pan
  1054.  class gold_coin_class;
  1055. Object coin4 "gold coin" left_pan
  1056.  class gold_coin_class;
  1057. Object coin5 "gold coin" right_pan
  1058.  class gold_coin_class;
  1059. Object coin6 "silver coin" right_pan
  1060.  class silver_coin_class;
  1061. Object coin7 "silver coin" right_pan
  1062.  class silver_coin_class;
  1063. Object crumpled_scroll "crumpled scroll" left_pan
  1064.  class scroll_class,
  1065.   with name "crumpled";
  1066.  
  1067. Object urbzig_spell "turn a dangerous object into a harmless one"
  1068.        crumpled_scroll
  1069.  class spell_class,
  1070.   with name "urbzig",
  1071.        magic
  1072.        [;  if (second==0) "The spell fizzles away.";
  1073.            if (second==player) "It's a matter of opinion, isn't it?";
  1074.            if (second==helistars_book or mace || second has is_cube)
  1075.            {   CDefArt(second); remove second;
  1076.                if (second==mace && cyclops in location)
  1077.                {   remove cyclops; move eye_cube to location;
  1078.                    " turns into a featureless white cube just as the cyclops \
  1079.                     was about to hit you with it.  Mightily embarrassed \
  1080.                     by this, he drops the cube and runs off!";
  1081.                }
  1082.                print " turns into a moth and flutters away.^";
  1083.                rtrue;
  1084.            }
  1085.            print "Nothing obvious happens.  Perhaps "; DefArt(second);
  1086.            " isn't so very dangerous after all.";
  1087.        ],
  1088.        unmagic
  1089.        [;  if (second==0) "The spell fizzles away.";
  1090.            if (second==player) "It's a matter of opinion, isn't it?";
  1091.            if (second has static || second has scenery)
  1092.            {   print "Your spell is too weak for something quite as \
  1093.                       monumentally harmless as "; DefArt(second); ".";
  1094.            }
  1095.            if (second==helistars_book or snake || second has is_cube
  1096.                || second==cyclops or mace)
  1097.                "Nothing obvious happens.";
  1098.            if (second in player)
  1099.            {   remove second; deadflag=1;
  1100.                "Suddenly, a tarantula races up your arm to your throat!  \
  1101.                 Perhaps it was unwise to gizbru something you were \
  1102.                 actually holding.";
  1103.            }
  1104.            if (cyclops has general)
  1105.                "Nothing happens.  Perhaps that's just as well, \
  1106.                 after the last time.";
  1107.            move cyclops to location;
  1108.            remove second; give cyclops general; StartTimer(cyclops, 5);
  1109.            CDefArt(second); " is replaced by a buck-toothed cyclops \
  1110.                 wielding a mace!";
  1111.        ];
  1112.  
  1113. Object cyclops "buck-toothed cyclops"
  1114.   with name "buck" "toothed" "buck-toothed" "cyclops",
  1115.        initial "A huge buck-toothed cyclops menaces you, armed with a \
  1116.                 heavy mace!",
  1117.        before
  1118.        [;  Cast: if (the_spell_was == bozbar_spell)
  1119.                      "Does the term ~death wish~ mean anything to you?";
  1120.                  if (the_spell_was == urbzig_spell)
  1121.                      "The cyclops bellows with glee as your spell has \
  1122.                       no effect.  (After all, he wouldn't be ~dangerous~ if \
  1123.                       an urbzig spell worked on him, would he?)";
  1124.        ],
  1125.        life [; "He roars incoherently, swinging the mace!"; ],
  1126.        time_left 0,
  1127.        time_out
  1128.        [;  if (self notin location)
  1129.            {   remove self; rtrue;
  1130.            }
  1131.            deadflag=1; remove mace; remove cyclops;
  1132.            "Feeling that he's given you quite long enough to explain why \
  1133.             you made such a mess of his life, he swings the great mace \
  1134.             maniacally down on you!";
  1135.        ],
  1136.        each_turn
  1137.        [ i; i=random(4); if (i==1) "^The cyclops leaps and bellows!";
  1138.             if (i==2)
  1139.               "^Whirling the mace, the cyclops jabbers at you incoherently.";
  1140.             if (i==3)
  1141.               "^The cyclops is losing patience (the appropriate cyclops \
  1142.                 word is untranslatable into English, but approximately means \
  1143.                 ~forbearance in not smashing all nearby skulls~).";
  1144.             "^The cyclops jabs you with the mace, almost breaking your rib.";
  1145.        ],
  1146.   has  animate transparent;
  1147.  
  1148. Nearby mace "mace"
  1149.   with name "heavy" "mace" "axe",
  1150.        description "It looks much too heavy for you to even lift.";
  1151.  
  1152. Nearby eye_cube "cube"
  1153.  class cube_class,
  1154.   with initial
  1155.          "A featureless white cube lies where the cyclops dropped it.";
  1156.  
  1157. ! ----------------------------------------------------------------------------
  1158. !   The Footpath and the carpet
  1159. ! ----------------------------------------------------------------------------
  1160.  
  1161. Object Footpath "Gorse Bushes"
  1162.   with description
  1163.            "The footpath from the cave mouth runs into dense, impenetrable \
  1164.             gorse bushes.  Perhaps it wasn't so much a footpath as a rill \
  1165.             in the earth where roots wouldn't take; anyway, there's no way \
  1166.             but back south.",
  1167.        s_to Cave_Mouth
  1168.   has  light;
  1169.  
  1170. Nearby carpet "beautiful red carpet"
  1171.   with name "beautiful" "magic" "red" "carpet",
  1172.        initial
  1173.           "Slung over one of the gorse bushes is a beautiful red carpet.",
  1174.        description
  1175.           "This is a carpet of unusual design. It is red, beautifully woven \
  1176.            and bears a pattern of cubes.",
  1177.        before
  1178.        [ i;  Receive:
  1179.                  if (self notin location || self hasnt moved)
  1180.                      "Not until the carpet's on the ground, you can't.";
  1181.            Ride: <<Enter self>>;
  1182.            Enter:
  1183.                  if (self notin location || self hasnt moved)
  1184.                      "Not until the carpet's on the ground, you can't.";
  1185.                  if (location==Temple)
  1186.                      "Mysteriously, the carpet rucks and pulls until you're \
  1187.                       thrown off.  It settles back on the white floor with a \
  1188.                       contented sigh.";
  1189.                  if (location==In_Cave)
  1190.                      "The carpet rises suddenly, crashing into the roof of \
  1191.                       cave and throwing you back off again.  Painfully.";
  1192.                  if (location==Bazaar) i=Up_Road; else i=Bazaar;
  1193.                  print "The carpet rises suddenly into the fluffy white \
  1194.                         clouds, and after a headlong journey deposits you...^";
  1195.                  move self to i;
  1196.                  PlayerTo(i,1); move player to self; <<Look>>;
  1197.            Take: if (player in self) "Not while you're on it!";
  1198.                  for (i=child(self):i~=0:i=child(self))
  1199.                  {   move i to location;
  1200.                      print "(Dislodging "; DefArt(i); print ")^";
  1201.                  }
  1202.        ],
  1203.   has  supporter enterable;
  1204.  
  1205. ! ----------------------------------------------------------------------------
  1206. !   A Bazaar Lottery
  1207. ! ----------------------------------------------------------------------------
  1208.  
  1209. Object Bazaar "Crowded Bazaar"
  1210.   with description
  1211.            "This is a crowded, noisy bazaar.  Directly in front of you is \
  1212.             a lottery!  But the contemptuous-looking barker is doing a \
  1213.             very poor trade: hardly anyone wants his first prize, the \
  1214.             big cuddly toy elephant, or even his nineteenth prize, a \
  1215.             featureless white cube.",
  1216.        each_turn
  1217.        [ i; i=random(4);
  1218.             if (i==1)
  1219.                 "^~Roll up!  Roll up!  One silver piece for three goes!~";
  1220.             if (i==2)
  1221.                 "^~Come on, then!  Just a silver coin gets you three!~";
  1222.             if (i==3)
  1223.                 "^~Think what you could win, all for one silver coin!~";
  1224.             "^~This could be your lucky day!~";
  1225.        ],
  1226.        before
  1227.        [;   Learn:
  1228.                 "~None of that!~ snaps the barker angrily, putting you off \
  1229.                  your study habits.  He mutters about ~Enchanter cheats~, \
  1230.                  but under the circumstances you decide to let the insult \
  1231.                  pass.";
  1232.        ],
  1233.        cant_go "Everywhere, the crowds of jabbering natives block your way \
  1234.            to all the good stalls.  In fact, the only one you can get at is \
  1235.            this dismal lottery.",
  1236.   has  light;
  1237.  
  1238. global last_called = 1;
  1239.  
  1240. Nearby board "lottery board"
  1241.   with number 0,
  1242.        name "board" "lottery" "holes",
  1243.        description
  1244.            "There are a hundred holes each way, making, um, let's see, yes, \
  1245.             ten thousand tickets in all.  Still, there are nineteen prizes, \
  1246.             so your odds must be, oh, well, not too awful anyway.",
  1247.        before
  1248.        [ i; if (action==##LetGo)
  1249.             {    if (self.number==0) "The barker stabs you in the chest with \
  1250.                     his finger.  ~That's a silver coin to you, bub!~";
  1251.  
  1252.                  for (i=taken_t1: i<=taken_t6: i++)
  1253.                      if (last_called == i.number)
  1254.                          "That ticket's already taken.";
  1255.  
  1256.                  self.number=self.number - 1;
  1257.                  for (i=taken_t1: i<=taken_t6: i++)
  1258.                      if (parent(i)==0)
  1259.                      {   i.number = last_called; itobj = i;
  1260.                          move i to player; give i moved proper;
  1261.                          print "You take "; DefArt(i); " out of the board.";
  1262.                      }
  1263.             }
  1264.             if (action~=##Examine) "The barker is burly, and won't let you \
  1265.                  tamper with the board.";
  1266.        ],
  1267.        initial
  1268.            "Behind the barker is a huge drilled board, and inside each little \
  1269.             numbered hole is a rolled-up lottery ticket."
  1270.   has  static container open;
  1271.  
  1272. Class  ticket_class
  1273.   with number -1, name "ticket",
  1274.        description
  1275.        [;  if (self.number==2306) "It is labelled ~First Prize~!";
  1276.            if (self.number==5802) "It is labelled ~Nineteenth Prize~.";
  1277.            "~You lose,~ says the ticket, with a smily face.  ~Try again!~";
  1278.        ],
  1279.        short_name
  1280.        [;  if (self.number==-1) rfalse;
  1281.            print "lottery ticket ", self.number; rtrue;
  1282.        ],
  1283.        parse_name
  1284.        [ i j w;
  1285.            if (NextWord()~='lottery' or 'ticket') return 0;
  1286.            i=1;
  1287.            if (NextWord()=='lottery' or 'ticket') { i++; wn++; }
  1288.            w=TryNumber(wn-1);
  1289.            if (w==-1000) return i;
  1290.            if (w==0) return 0;
  1291.            if (self.number==-1)
  1292.            {   for (j=taken_t1: j<=taken_t6: j++)
  1293.                    if (w == j.number) rfalse;
  1294.            }
  1295.            else
  1296.            {   if (self.number~=w) return 0;
  1297.            }
  1298.            i++; last_called = w; return i;
  1299.        ],
  1300.        before
  1301.        [;  Examine:
  1302.                if (self in board) "That would be cheating!";
  1303.            Cast: "~Get outta here, bub!~, the barker says, disgusted.";
  1304.        ];
  1305.  
  1306. Object ticket_in_board "rolled-up ticket" board
  1307.  class ticket_class;
  1308. Object taken_t1 "t1" class ticket_class;
  1309. Object taken_t2 "t2" class ticket_class;
  1310. Object taken_t3 "t3" class ticket_class;
  1311. Object taken_t4 "t4" class ticket_class;
  1312. Object taken_t5 "t5" class ticket_class;
  1313. Object taken_t6 "t6" class ticket_class;
  1314.  
  1315. Object barker "barker" Bazaar
  1316.   with name "barker" "burly" "man",
  1317.        number 0,
  1318.        description
  1319.            "A boxer gone to seed who failed as a magician all down the \
  1320.             coast, that'd be your guess.",
  1321.        life
  1322.        [;  Attack, Kiss: "No way.  He must weigh twice what you do.";
  1323.            Ask:  if (second=='prize' or 'prizes')
  1324.                     "~Just one silver coin and a prize could be yours!~";
  1325.                  if (second=='white' or 'featureless' or 'cube')
  1326.                     "He blows the dust off it.  ~Genuine antique, that.~";
  1327.                  if (second=='elephant' or 'toy' or 'cuddly')
  1328.                     "~Good quality merchandise,~ he says, in a way that \
  1329.                      suggests he can only spell one of those three words.";
  1330.                  if (second=='ticket' or 'tickets' or 'lottery')
  1331.                     "~Three tickets for one silver coin!~";
  1332.                  "~Just play the game, bub.~";
  1333.            Order, Answer: "The barker glowers at you.";
  1334.            Give: if ((noun.&name)-->0 == 'ticket')
  1335.                  {   remove noun;
  1336.                      if (noun.number==2306)
  1337.                      {   move elephant to player; give elephant moved;
  1338.                          Bazaar.description =
  1339.            "This is a crowded, noisy bazaar.  Directly in front of you is \
  1340.             the lottery!";
  1341.                          "With very bad grace, the barker shoves the \
  1342.                           cuddly toy elephant into your arms.";
  1343.                      }
  1344.                      if (noun.number==5802)
  1345.                      {   move barker_cube to player; give barker_cube moved;
  1346.                          Bazaar.description =
  1347.            "This is a crowded, noisy bazaar.  Directly in front of you is \
  1348.             the lottery!";
  1349.                          score=score+5;
  1350.                          "With concealed relief, the barker shoves the \
  1351.                           featureless white cube into your hands.";
  1352.                      }
  1353.                      "~Bad luck!  You lose!~";
  1354.                  }
  1355.                  if (self.number==2) "~You've had enough goes already!~ he \
  1356.                      growls.  No wonder trade is bad.";
  1357.                  if (noun hasnt is_coin) "~What do you call that?  One silver \
  1358.                      coin to play!~";
  1359.                  if ((noun.&name)-->0 == 'bronze')
  1360.                      "~Bronze!  Not a chance, sunshine.~";
  1361.                  remove noun;
  1362.                  board.number = board.number + 3; self.number=self.number+1;
  1363.                  if ((noun.&name)-->0 == 'gold')
  1364.                      "Gleefully the barker snatches the gold coin.  ~Sorry \
  1365.                       bub, no change.  Business is slack today!~";
  1366.                  "Grudgingly the barker takes the silver coin and stands \
  1367.                   back to let you at the board, arms folded.";
  1368.        ],
  1369.        before
  1370.        [;  Cast: if (the_spell_was == bozbar_spell)
  1371.                      "He's not that much of an animal.";
  1372.                  if (the_spell_was == lobal_spell)
  1373.                      "His problem is listening, not hearing.";
  1374.                  if (the_spell_was == caskly_spell)
  1375.                      "For a moment his hair seems to comb itself.  Irritated, \
  1376.                       he ruffles it again, and the spell dies an ignominious \
  1377.                       death.";
  1378.                  if (the_spell_was == yomin_spell)
  1379.                  {   if (elephant has moved || barker_cube has moved)
  1380.                          "The barker's mind is a heap of grumbles about lost \
  1381.                           prizes and scrawny Enchanters.";
  1382.                      if (self hasnt general)
  1383.                      {   give self general;
  1384.                          "~Hope that scrawny Enchanter doesn't pick 2306!~ \
  1385.                           thinks the barker (slowly).";
  1386.                      }
  1387.                      "~If that mark does win, hope it's only worthless \
  1388.                        old 5802,~ ponders the barker.";
  1389.                  }
  1390.        ],
  1391.   has  animate scenery;
  1392.  
  1393. Object prizes "prizes" Bazaar
  1394.   with name "prize" "prizes",
  1395.        before [; "~Hands off those prizes!~"; ],
  1396.   has  scenery;
  1397.  
  1398. Object elephant "cuddly toy elephant"
  1399.   with name "cuddly" "toy" "elephant",
  1400.        description "Pink, cuddly, toy, elephant.  Says it all, really.",
  1401.        before
  1402.        [;  Cast: if (the_spell_was == bozbar_spell)
  1403.                      "Let me get this straight.  You, the enchanter who \
  1404.                       defeated Krill, the head of the Borphee Guild \
  1405.                       himself...  are attempting to grow wings on a pink \
  1406.                       cuddly elephant?";
  1407.        ];
  1408.  
  1409. Object barker_cube "cube"
  1410.  class cube_class;
  1411.  
  1412. ! ----------------------------------------------------------------------------
  1413. !   The spells in Helistar's grimoire
  1414. ! ----------------------------------------------------------------------------
  1415.  
  1416. Object lleps_spell "reverse effect of memorised spell"
  1417.  class spell_class,
  1418.   with name "lleps",
  1419.        magic
  1420.        [;   if (second==0 || parent(second)~=memory)
  1421.                 "The spell backfires, painfully.";
  1422.             if (second.number==100)
  1423.                 "You know that spell too well for your mind to be able \
  1424.                  to accept the change.";
  1425.             if (second has general) give second ~general;
  1426.             else give second general;
  1427.             print "Your mind wrenches as "; DefArt(second);
  1428.             " reverses itself.";
  1429.        ],
  1430.        unmagic
  1431.        [;   RunRoutines(self,magic); rtrue;
  1432.        ];
  1433.  
  1434. Object mortin_spell "cause immediate death of caster"
  1435.  class spell_class,
  1436.   with name "mortin",
  1437.        magic
  1438.        [;   deadflag=1;
  1439.             "You really can't fault Helistar on this one.  Death is \
  1440.              absolutely immediate, like a sudden blackout curtain...";
  1441.        ],
  1442.        unmagic
  1443.        [;   prepared_flag=1;
  1444.             "Nothing quite happens... and yet you feel enormously more \
  1445.              confident as you go about this dangerous world.";
  1446.        ];
  1447.  
  1448. ! ----------------------------------------------------------------------------
  1449. !   Death and the Boneyard
  1450. ! ----------------------------------------------------------------------------
  1451.  
  1452. [ AfterLife i;
  1453.   if (prepared_flag==0) rfalse;
  1454.   
  1455.   if (parent(player)==Balance_Room)
  1456.       "^^Your foresight in preparing a resurrection was wasted.  The \
  1457.          tangled magic of the Balance Room coiled around your puny \
  1458.          enchantment like a constricting serpent.";
  1459.  
  1460.   prepared_flag=0; deadflag=0; hearing_good=0;
  1461.   i=memory.capacity; if (i>1) memory.capacity = i-1;
  1462.   i=parent(player);
  1463.   while (child(player)~=0) move child(player) to i;
  1464.   move spell_book to player;
  1465.  
  1466.   print "^^With great foresight you prepared yourself for resurrection...  \
  1467.            Your mind feels a little weaker, but at least you're alive.^";
  1468.   PlayerTo(Boneyard);
  1469. ];
  1470.  
  1471. Object Boneyard "Boneyard"
  1472.   with name "bones" "blades" "shoulder" "skulls",
  1473.        description
  1474.           "This is a room of bones.  Shoulder blades make up the floor, \
  1475.            skulls the walls and leg-bones the door frames. The west exit \
  1476.            leads into darkness, but the doorway to the north opens onto a \
  1477.            seemingly normal grassy scene.",
  1478.        n_to Grasslands,
  1479.        w_to "Some magical force blocks your way.",
  1480.        before
  1481.        [;  Examine, Search:
  1482.                if (noun==w_obj) "You can make out nothing to the west.";
  1483.        ],
  1484.   has  light;
  1485.  
  1486. Nearby worthless_scroll "worthless scroll"
  1487.  class scroll_class,
  1488.   with initial "You are almost treading on a worthless scroll.",
  1489.        name "worthless";
  1490.  
  1491. Object filfre_spell "produce gratuitous fireworks" worthless_scroll
  1492.  class spell_class,
  1493.   with name "filfre",
  1494.        magic
  1495.        [;    if (self hasnt scored) { score++; give self scored; }
  1496.             "A brief shower of gratuitous fireworks spells out:^^\
  1497.              The masterly Enchanter trilogy was written by Marc Blank, \
  1498.              David Lebling and Steve Meretzky.";
  1499.        ],
  1500.        unmagic
  1501.        [;   "A lengthy shower of artistically justified fireworks spells out:^^\
  1502.              The masterly Enchanter trilogy was written by Jane Austen, \
  1503.              Emily Bronte and Edgar Allen Poe.";
  1504.        ];
  1505.  
  1506. ! ----------------------------------------------------------------------------
  1507. !   The Cubical Temple
  1508. ! ----------------------------------------------------------------------------
  1509.  
  1510. Object Track "Track, outside Temple"
  1511.   with description
  1512.           "This is the end of a long track winding through desolate hills, \
  1513.            which runs back west up to the ridge.",
  1514.        before
  1515.        [;   Listen:
  1516.                 if (hearing_good==0) "The chanting is too quiet to make out.";
  1517.                 "The endlessly repeating threnody of the monks tells of \
  1518.                  the legend of one who will some day enlighten their order, \
  1519.                  and so be taken up to a higher plane.  He (or she, \
  1520.                  presumably) is known as The Four-Cubed One.";
  1521.        ],
  1522.        w_to Up_Road, u_to Up_Road
  1523.   has  light;
  1524.  
  1525. Nearby Temple "cubical Temple"
  1526.   with name "temple" "cubical" "cube" "enormous",
  1527.        before
  1528.        [ i j;
  1529.          Enter: "The Temple is featureless and unbroken.  Perhaps the top \
  1530.                  is open, because the sound must come from somewhere... \
  1531.                  but you wouldn't bet on it.";
  1532.          Cast:   if (the_spell_was == rezrov_spell)
  1533.                     "The huge temple remains impassive at your relatively \
  1534.                      puny enchantment.";
  1535.                  if (the_spell_was == frotz_spell)
  1536.                  {   objectloop (i in player) if (i has is_cube) j++;
  1537.                      if (j==0) "The temple shakes, but then is still again.";
  1538.                      if (j<4) "The temple shakes!  White light plays \
  1539.                          over your hands and possessions, but then all is \
  1540.                          still again.";
  1541.                      print "The temple shakes and white light bathes you.  \
  1542.                          Smoothly it unfolds itself in a four-dimensional \
  1543.                          way your senses can barely comprehend.  All you \
  1544.                          know is that when it is over, \
  1545.                          you find yourself in...^";
  1546.                      hearing_good=0; score=score+5;
  1547.                      PlayerTo(Balance_Room); rtrue;
  1548.                  }
  1549.        ],
  1550.        describe
  1551.        [;   print "^You stand outside an enormous temple in the shape of a \
  1552.                    perfect, featureless white cube, four hundred feet on a \
  1553.                    side.  From somewhere within you hear the ";
  1554.             if (hearing_good==1) print "bellowing noise";
  1555.             else print "tiny sound";
  1556.             " of the monks chanting.";
  1557.        ],
  1558.        description
  1559.            "It's much like every other gigantic temple in the shape of a \
  1560.             featureless white cube you've ever seen.  No obvious way in.",
  1561.   has  static;
  1562.  
  1563. ! ----------------------------------------------------------------------------
  1564. !   Inside the Temple
  1565. ! ----------------------------------------------------------------------------
  1566.  
  1567. Object Balance_Room "Balance Room"
  1568.   with description
  1569.            "This seems to be the inside of a featureless white cube, forty \
  1570.             feet on a side.  The air is stale and there is no exit.",
  1571.   has  light;
  1572.  
  1573. Nearby balance_meter "image of the scales"
  1574.   with name "image" "scales" "of" "pair", article "the",
  1575.        initial "The image of a pair of scales hangs high in the air.  One \
  1576.                 pan is much lower than the other.",
  1577.        before [; "It's only an image."; ],
  1578.   has  static;
  1579.  
  1580. Nearby dusty_podium "dusty podium"
  1581.   with name "podium" "dusty" "cobwebs" "cobwebbed",
  1582.        initial "Far below the scales, in the centre of the ~floor~, is a \
  1583.                 predictably-shaped podium, but it is so dusty and \
  1584.                 cobwebbed that you can't see what it once was.",
  1585.        before
  1586.        [;  Cast: if (the_spell_was == caskly_spell)
  1587.                     "Nice try, but it is protected from enchantment.";
  1588.                 "However dusty it is, the podium is still protected from \
  1589.                  casual enchantment.";
  1590.            Rub:  remove self; move balance_key to Balance_Room;
  1591.                  itobj = balance_key;
  1592.                 "No substitute for old-fashioned hard work, sometimes, \
  1593.                  and after much patient (sneezy) scrubbing, the podium \
  1594.                  appears in its true white glory.  Set into it are four \
  1595.                  sockets, arranged in a two by two square.";
  1596.        ],
  1597.   has  static;
  1598.  
  1599. Object balance_key "podium"
  1600.   with name "podium" "pedestal" "platform" "cubical",
  1601.        initial "Far below the scales, in the centre of the ~floor~, is a \
  1602.                 predictably-shaped podium.  Set into it are four sockets, \
  1603.                 arranged in a two by two square.",
  1604.   has  static supporter;
  1605.  
  1606. Nearby sockets "two by two square"
  1607.   with name "square" "two" "by" "two",
  1608.        before
  1609.        [ i;  if (action~=##Examine || number_filled==0)
  1610.               "You'll have to say which socket you mean.  \
  1611.                (Let's call them ~top left~, ~bottom right~ and so on.)";
  1612.            objectloop (i in self)
  1613.            {   CDefArt(i);
  1614.                if (child(i)==0) print " is empty.^";
  1615.                else { print " contains "; IndefArt(child(i)); print ".^"; }
  1616.            }
  1617.            rtrue;
  1618.        ],
  1619.   has  static;
  1620.  
  1621. Class  socket_class
  1622.   with name "socket", article "the",
  1623.        before
  1624.        [;  Cast:  "The sockets are proof against magic.";
  1625.            Examine: CDefArt(self); print ", cubical and slightly more \
  1626.                     than four inches on a side, is decorated with ";
  1627.                     print_paddr self.description;
  1628.                     if (child(self)==0) ".";
  1629.                     print ", and contains "; IndefArt(child(self)); ".";
  1630.            Receive: if (noun hasnt is_cube) "The socket rejects that.";
  1631.                     if (child(self)~=0)
  1632.                        "There is already a cube in that socket.";
  1633.        ],
  1634.        after
  1635.        [;  LetGo:  number_filled--;
  1636.                    "With much struggle, you manage to pull the cube away.";
  1637.            Receive: number_filled++;
  1638.            if (number_filled==4)
  1639.            {   if (snakes_cube in bl_socket
  1640.                    && barker_cube in ul_socket
  1641.                    && cave_cube in br_socket
  1642.                    && eye_cube in ur_socket)
  1643.                {   deadflag=2; score=score+5;
  1644.                   "As you place the final cube into the sockets, you feel \
  1645.                    imbued with celestial wisdom (more so than usually).  \
  1646.                    You find yourself growing to the height of the cube, so \
  1647.                    that you pull the balances back level by hand, and then \
  1648.                    you grow still further, out of the temple until it is but \
  1649.                    a cube in your hand, and you are a giant towering over \
  1650.                    the land.^^\
  1651.                    Then, of course, you wake up, glumly realising it's time \
  1652.                    to go to your job at the new Borphee Laboratories and \
  1653.                    all those Wheatstone bridge experiments.  But at least \
  1654.                    you can dream about the old days.";
  1655.                }
  1656.               "The sockets are all full now, but that doesn't mean \
  1657.                anything's happened.";
  1658.            }
  1659.           "The cube is a predictably perfect fit in the socket.";
  1660.        ],
  1661.   has  static container open;
  1662.  
  1663. Nearby bl_socket "bottom left socket"
  1664.  class socket_class
  1665.   with name "bottom" "left" "serpent",
  1666.        description "a serpent";
  1667.  
  1668. Nearby ul_socket "top left socket"
  1669.  class socket_class
  1670.   with name "top" "left" "bazaar",
  1671.        description "a scene in a bazaar";
  1672.  
  1673. Nearby br_socket "bottom right socket"
  1674.  class socket_class
  1675.   with name "bottom" "right" "cave",
  1676.        description "an engraving of a rocky cave";
  1677.  
  1678. Nearby ur_socket "top right socket"
  1679.  class socket_class
  1680.   with name "top" "right" "eye",
  1681.        description "an eye";
  1682.  
  1683. ! ----------------------------------------------------------------------------
  1684. !   That's all of the object definitions: just a little code and grammar left
  1685. ! ----------------------------------------------------------------------------
  1686.  
  1687. [ Initialise;
  1688.  
  1689.   location = Hut;
  1690.   move burin to player; move coin1 to player; move spell_book to player;
  1691.  
  1692.   thedark.description =
  1693.       "It is pitch black.  You are likely to be eaten by a grue.";
  1694.   ! (In fact you are stone-cold certain not to be, but never mind.)
  1695.  
  1696.   spell_book.magic = all_my_spells;
  1697.   <Learn spell_book gnusto_spell>;
  1698.   <Learn spell_book frotz_spell>;
  1699.   <Learn spell_book yomin_spell>;
  1700.   <Learn spell_book rezrov_spell>;
  1701.  
  1702.   helistars_book.magic = helistars_spells;
  1703.   <Learn helistars_book frotz_spell>;
  1704.   <Learn helistars_book lleps_spell>;
  1705.   <Learn helistars_book mortin_spell>;
  1706.  
  1707.   print "^^^^^This transcript is not from the Enchanter trilogy, but it \
  1708.          does show most of the usual things you can do in those stories...^^";
  1709.   print "You feel a little confused as to how you got here.  Something \
  1710.          to do with Helistar!  That's right, and how the world is so far \
  1711.          off balance nowadays, after the Great Change.^^";
  1712.  
  1713. ];
  1714.  
  1715. [ PrintRank;
  1716.   print ", earning you the rank of ";
  1717.   if (score >= 50)  "Scientist.";
  1718.   if (score >= 40)  "Spellbreaker.";
  1719.   if (score >= 30)  "Sorcerer.";
  1720.   if (score >= 20)  "Enchanter.";
  1721.   if (score >= 10)  "novice Enchanter.";
  1722.   "lost dreamer.";
  1723. ];
  1724.  
  1725. [ DiagnoseSub i;
  1726.   i=memory.capacity;
  1727.   if (i==5) "You feel fine, and your memory is unimpaired.";
  1728.   if (i==4) "You feel shaky after your brush with death, but your mental \
  1729.              faculties seem sound.";
  1730.   if (i==3) "For someone who has died twice, you're in reasonable shape.";
  1731.   "How many times have you died now?  Your memory isn't what it was.";
  1732. ];
  1733.  
  1734. ! ----------------------------------------------------------------------------
  1735. !   Grammar extensions needed by the spell-casting and cube-writing rules:
  1736. ! ----------------------------------------------------------------------------
  1737.  
  1738. Include "Grammar";
  1739.  
  1740. [ AnyWord; the_named_word=wn++; return burin; ];
  1741.  
  1742. Verb "write" "scribe"
  1743.                 * AnyWord "on" noun              -> WriteOn;
  1744. Verb "copy"     * scope=ReadableSpell "to" noun  -> CopyTo;
  1745. Verb "who" "what"
  1746.                 * "is"  scope=Topic              -> Query
  1747.                 * "was" scope=Topic              -> Query;
  1748. Verb "spells" "memory"
  1749.                 *                                -> Spells;
  1750. Verb "learn" "memorise" "memorize"
  1751.                 * scope=ReadableSpell            -> Learn;
  1752. Extend "examine" first
  1753.                 * scope=ReadableSpell            -> Examine;
  1754. Verb "c#cast"
  1755.                 *                                -> CastOne
  1756.                 * noun                           -> CastOne;
  1757. Verb "cast"
  1758.                 * is_spell                       -> Cast
  1759.                 * is_spell "at" noun             -> Cast
  1760.                 * is_spell "on" noun             -> Cast;
  1761. Verb "diagnose" "health"
  1762.                 *                                -> Diagnose;
  1763.  
  1764. ! ----------------------------------------------------------------------------
  1765. !   And one for the game itself.
  1766. ! ----------------------------------------------------------------------------
  1767.  
  1768. Verb "ride" "mount" "straddle"
  1769.                 * creature                       -> Ride
  1770.                 * noun                           -> Enter;
  1771. Verb "flip" "toss" * is_coin                     -> TossCoin;
  1772.  
  1773. end;
  1774.